package fictional.GUI;

import fictional.BL.BL;
import fictional.Common.GenderItem;
import fictional.Common.IBL;
import fictional.Common.PlaceItem;
import fictional.Common.SpeciesItem;
import fictional.Common.User;
import fictional.DAL.DAL;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.sql.SQLException;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.UIManager;
import org.jdesktop.application.Application;
import org.jdesktop.application.ApplicationContext;
import org.jdesktop.application.TaskMonitor;
import org.jdesktop.application.TaskService;

/**
 * A class which is responsible for logging into the system
 * and handling connection issues.
 */
public class Login
{
    private TaskMonitor taskMonitor;
    private TaskService taskService;
    private LoginTask loginTask;
    private IBL BL;
    private GUI gui;
    JFrame frame;
    JTextField userTextField;
    JPasswordField passwordField;
    JButton loginButton;
    JButton connectionSetupButton;
    JButton newUserButton;
    JFrame loginFrame;
    BusyIconPopup busyIconPopup;
    DefaultTask currentlyRunningTask;
    String connectionString;
    String connectionUsername;
    String connectionPassword;

    public Login()
    {
        createLoginFrame();
    }
    
    @SuppressWarnings("serial")
	private void createLoginFrame() {
    	
        loginFrame = new JFrame();
        loginFrame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        loginFrame.setTitle("Welcome To Ficbook");
        loginFrame.setIconImage(new ImageIcon(getClass().getResource("resources/windowIcon.gif")).getImage());
        
        try
        {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        
    	JPanel panelBgImg = new JPanel()
        {
            public void paintComponent(Graphics g) 
            {
                Image img = new ImageIcon(getClass().getResource("/fictional/GUI/resources/splashImage.gif")).getImage();
                Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
                setPreferredSize(size);
                setMinimumSize(size);
                setMaximumSize(size);
                setSize(size);
                setLayout(null);
                g.drawImage(img, 0, 0, null);
            } 
        };
        
        loginFrame.setBackground(Color.white);

        loginFrame.getContentPane().add(panelBgImg);

        // Set initial size
        loginFrame.setSize(376, 421);
        loginFrame.setResizable(false);
        loginFrame.setLocationRelativeTo(null);
        
        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints gc = new GridBagConstraints();
        gc.fill = GridBagConstraints.HORIZONTAL;
        
        panelBgImg.setLayout(layout);
        
        JLabel userLabel = new JLabel("Username: ");
        gc.gridx = 0;
        gc.gridy = 1;
        gc.insets = new Insets(175, 10, 10, 10);
        gc.gridwidth = 1;
        
        panelBgImg.add(userLabel, gc);
        
        userTextField = new JTextField();
        userTextField.setText("Inigo Montoya");
        gc.gridx = 1;
        gc.gridy = 1;
        gc.gridwidth = 2;
        gc.insets = new Insets(175, 0, 10, 10);
        panelBgImg.add(userTextField, gc);
        
        JLabel passwordLabel = new JLabel("Password: ");
        gc.gridx = 0;
        gc.gridy = 2;
        gc.weightx = 0.0;
        gc.gridwidth = 1;
        gc.insets = new Insets(0, 10, 10, 10);
        gc.gridwidth = 1;
        
        panelBgImg.add(passwordLabel, gc);
        
        passwordField = new JPasswordField();
        passwordField.setText("Inigo Montoya");
        gc.gridx = 1;
        gc.gridy = 2;
        gc.weightx = 1.0;
        gc.gridwidth = 2;
        gc.insets = new Insets(0, 0, 10, 10);
        panelBgImg.add(passwordField, gc);
        
        JButton loginButton = new JButton("Login");
        loginButton.setMaximumSize(new java.awt.Dimension(100, 23));
        loginButton.setMinimumSize(new java.awt.Dimension(100, 23));
        loginButton.setPreferredSize(new java.awt.Dimension(100, 23));
        gc.gridx = 0;
        gc.gridy = 3;
        gc.gridwidth = 2;
        gc.insets = new Insets(20, 60, 10, 10);
        gc.fill = GridBagConstraints.NONE;
        gc.anchor = GridBagConstraints.WEST;
        
        loginButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                loginButtonMouseClicked(evt);
            }
        });
        
        panelBgImg.add(loginButton, gc);
        
        newUserButton = new JButton("New User?");
        newUserButton.setMaximumSize(new java.awt.Dimension(100, 23));
        newUserButton.setMinimumSize(new java.awt.Dimension(100, 23));
        newUserButton.setPreferredSize(new java.awt.Dimension(100, 23));
        gc.gridx = 0;
        gc.gridy = 3;
        gc.insets = new Insets(20, 200, 10, 10);
        gc.anchor = GridBagConstraints.EAST;
        
        newUserButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                newUserButtonMouseClicked(evt);
            }
        });
        
        panelBgImg.add(newUserButton, gc);
        
		ConnectionSetupPopup popup = new ConnectionSetupPopup(this);
		popup.setLocationRelativeTo(loginFrame);
		popup.setVisible(true);
        
        ApplicationContext appC = Application.getInstance().getContext();
        taskMonitor = appC.getTaskMonitor();
        taskService = appC.getTaskService(); 
        
        busyIconPopup = new BusyIconPopup();
        
        TaskMonitor taskMonitor = this.taskMonitor;
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener()
        {
            public void propertyChange(java.beans.PropertyChangeEvent evt)
            {
            	if (currentlyRunningTask == null)
            	{
            		return;
            	}
            	
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName))
                {
                    startBusy();
                }
                else if ("done".equals(propertyName))
                {
                    stopBusy();
					if (!currentlyRunningTask.isSuccessful()) 
					{
						if (!currentlyRunningTask.isActionDone()) 
						{
							if (currentlyRunningTask.response.getException() instanceof SQLException)
							{
								SQLException sqlException = (SQLException)currentlyRunningTask.response.getException();
								if (sqlException.getSQLState().equals("08003"))
								{
									// the connection to database is closed
									loginFrame.setVisible(false);
									loginFrame.dispose();
									connect();
								}
								else
								{
									currentlyRunningTask.doInCaseOfFail();
								}
							}
							else
							{
								currentlyRunningTask.doInCaseOfFail();
							}
						}
					} 
					else if (currentlyRunningTask.isSuccessMessageNeeded) 
					{
						if (!currentlyRunningTask.isActionDone()) 
						{
		                    currentlyRunningTask.doInCaseOfSuccess();
						}
					}
					else
					{
	                    if (gui != null)
	                    {
	                    	gui.setVisible(true);
	                    	loginFrame.setVisible(false);
	                    }
					}
                }
            }
        });
		
	}

	public void setGUI(GUI gui)
    {
    	this.gui = gui;
    }

    @SuppressWarnings("deprecation")
	private void loginButtonMouseClicked(java.awt.event.MouseEvent evt)
    {
    	if (userTextField.getText().isEmpty() || passwordField.getText().isEmpty())
    	{
    		drawErrorMessage("Please do not leave any blank fields.", "Error Logging In");
    	}
        loginTask = new LoginTask(Application.getInstance());
        loginTask.setTask(BL, userTextField.getText(), passwordField.getText(), this);
        taskService.execute(loginTask);
        taskMonitor.setForegroundTask(loginTask);
        currentlyRunningTask = loginTask;
    }
    
    private void newUserButtonMouseClicked(java.awt.event.MouseEvent evt)
    {
    	NewUserPopup popup = new NewUserPopup(this, BL, loginFrame);
    	popup.setVisible(true);
    }
    
    public void addNewUser(User user, String name, GenderItem gender, SpeciesItem species, String organizations, PlaceItem birthplace, String occupations, String superPowers)
    {
        AddNewUserTask addNewUserTask= new AddNewUserTask(Application.getInstance());
        addNewUserTask.setTask(BL, this, user, name, gender, species, organizations, birthplace, occupations, superPowers);
        taskService.execute(addNewUserTask);
        taskMonitor.setForegroundTask(addNewUserTask);
        currentlyRunningTask = addNewUserTask;
    }
    
    public void loggedOut()
    {
    	gui.setVisible(false);
    	gui.dispose();
    	userTextField.setText("");
    	passwordField.setText("");
    	loginFrame.setVisible(true);
    }
    
    private void startBusy()
    {
    	loginFrame.setEnabled(false);
        busyIconPopup.start();
    }
    
    private void stopBusy()
    {
    	loginFrame.setEnabled(true);
        busyIconPopup.stop();
    }
    
    public void drawErrorMessage(String errorMessage, String errorTitle)
    {
    	JOptionPane.showMessageDialog(null, errorMessage, errorTitle, JOptionPane.OK_OPTION);
    }
    
    public void setNewUseDisplay(String username, String password)
    {
    	userTextField.setText(username);
    	passwordField.setText(password);
    }
    
    public IBL reconnect()
    {
		try
		{
			BL = new BL(new DAL(connectionString, connectionUsername, connectionPassword));
			return BL;
		} 
		catch (Exception e)
		{
			return null;
		}
    }

    public void connect()
    {
		try {
			BL = new BL(new DAL(connectionString, connectionUsername, connectionPassword));
			loginFrame.setVisible(true);
		} 
		catch (Exception e) 
		{
			String[] buttons = { "Try Reconnecting", "Change Paramaters", "Exit" };

		    int rc = JOptionPane.showOptionDialog(null, "An error has occured trying to connect to the database. What would you like to do?", "Error Connectiong To Databse",
		    		JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, buttons, buttons[2]);
		    
		    if (rc == 0)
		    {
		    	connect();
		    }
		    else if (rc == 1)
		    {
				ConnectionSetupPopup popup = new ConnectionSetupPopup(this, connectionString, connectionUsername, connectionPassword);
				popup.setLocationRelativeTo(loginFrame);
				popup.setVisible(true);
		    }
		    else if (rc == 2)
		    {
		    	loginFrame.setVisible(false);
		    	loginFrame.dispose();
		    }
		}
    }
    
	public void setConnectionParamaters(String connectionString, String connectionUsername, String connectionPassword) 
	{
		this.connectionString = connectionString;
		this.connectionUsername = connectionUsername;
		this.connectionPassword = connectionPassword;
		
		connect();
	}
	
	public void exit()
	{
		loginFrame.setVisible(false);
		loginFrame.dispose();
	}
}